//! 爬虫响应到 HttpEvent 的转换器

use crate::crawler::CrawlerResponse;
use good_mitm_passive_scan::{HttpEvent, EventMetadata, EventType};
use http::StatusCode;
use log::debug;
use std::collections::HashMap;

/// 响应转换器
pub struct ResponseConverter;

impl ResponseConverter {
    /// 将 CrawlerResponse 转换为 HttpEvent
    pub fn convert_to_http_event(response: CrawlerResponse) -> HttpEvent {
        let url = response.url.clone();

        // 解析URL以获取host和path
        let (host, path) = Self::parse_url(&url);

        // 转换响应头
        let headers = response.headers;

        // 创建事件元数据
        let metadata = EventMetadata {
            id: uuid::Uuid::new_v4().to_string(),
            timestamp: chrono::Utc::now(),
            event_type: EventType::Response,
            source_ip: "crawler".to_string(),
            host: host.clone(),
            connection_id: format!("crawler_{}", uuid::Uuid::new_v4()),
            duration_us: Some(response.response_time_ms * 1000), // 转换为微秒
        };

        // 计算body哈希
        let body_hash = Some(Self::hash_body(&response.body));

        // 提取内容类型
        let content_type = response.content_type.clone();

        // 构建 HttpEvent
        HttpEvent {
            metadata,
            method: None, // 响应事件不需要method
            uri: Some(url),
            status_code: Some(response.status.to_string()),
            headers: headers.clone(),
            body_hash,
            body_size: response.body.len(),
            content_type,
            user_agent: None, // 响应事件不需要user_agent
            query_params: Self::extract_query_params(&path),
            path: Some(path),
            version: headers.get("server").cloned(),
        }
    }

    /// 解析URL获取host和path
    fn parse_url(url: &str) -> (String, String) {
        if let Ok(parsed) = url::Url::parse(url) {
            let host = parsed
                .host_str()
                .unwrap_or("unknown")
                .to_string();
            let path = parsed.path().to_string();
            (host, path)
        } else {
            debug!("Failed to parse URL: {}", url);
            ("unknown".to_string(), "/".to_string())
        }
    }

    /// 提取查询参数
    fn extract_query_params(url: &str) -> Option<HashMap<String, String>> {
        if let Ok(parsed) = url::Url::parse(&format!("http://example.com{}", url)) {
            if let Some(query) = parsed.query() {
                let mut params = HashMap::new();
                for pair in query.split('&') {
                    if let Some((key, value)) = pair.split_once('=') {
                        params.insert(
                            urlencoding::decode(key).unwrap_or_default().to_string(),
                            urlencoding::decode(value).unwrap_or_default().to_string(),
                        );
                    }
                }
                if !params.is_empty() {
                    return Some(params);
                }
            }
        }
        None
    }

    /// 计算body哈希
    fn hash_body(body: &[u8]) -> String {
        use sha2::{Digest, Sha256};
        let mut hasher = Sha256::new();
        hasher.update(body);
        format!("{:x}", hasher.finalize())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_url() {
        let (host, path) = ResponseConverter::parse_url("https://example.com/api/users");
        assert_eq!(host, "example.com");
        assert_eq!(path, "/api/users");

        let (host, path) = ResponseConverter::parse_url("https://example.com:8080/test?param=value");
        assert_eq!(host, "example.com");
        assert_eq!(path, "/test");
    }

    #[test]
    fn test_extract_query_params() {
        let params = ResponseConverter::extract_query_params("/api/users?id=123&name=test");
        assert!(params.is_some());
        let params = params.unwrap();
        assert_eq!(params.get("id"), Some(&"123".to_string()));
        assert_eq!(params.get("name"), Some(&"test".to_string()));
    }

    #[test]
    fn test_hash_body() {
        let body = b"test body";
        let hash = ResponseConverter::hash_body(body);
        assert!(!hash.is_empty());
        assert_eq!(hash.len(), 64); // SHA256产生64个十六进制字符
    }
}
